package com.fengycx.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fengycx.constants.Constants;
import com.fengycx.pojo.domain.Login;
import com.fengycx.mapper.LoginMapper;
import com.fengycx.pojo.domain.LoginContext;
import com.fengycx.pojo.dto.AdminLoginDto;
import com.fengycx.pojo.dto.LoginInfoDto;
import com.fengycx.pojo.dto.LoginParamDto;
import com.fengycx.service.ILoginService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fengycx.service.IPermissionService;
import com.fengycx.template.WechatTemplate;
import com.fengycx.utils.AssertUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 登录表 服务实现类
 * </p>
 *
 * @author Cino
 * @since 2024-02-23
 */
@Service
public class LoginServiceImpl extends ServiceImpl<LoginMapper, Login> implements ILoginService {

    @Autowired
    private WechatTemplate wechatTemplate;

    @Autowired
    private IPermissionService permissionService;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public LoginInfoDto appLogin(LoginParamDto param) {

        String openId = wechatTemplate.getOpenId(param.getCode());
        AssertUtil.isNotNull(openId,"OpenId获取失败！");

        //两个字段都存在才能说明已注册相同账号
        Login loginInfo = super.getOne(new LambdaQueryWrapper<Login>()
                .eq(Login::getOpenId, openId)
                .eq(Login::getType, param.getType()));
        AssertUtil.isNotNull(loginInfo,"用户不存在，请注册！");

        //检查此账号是否之前已有登录；
        //为账号生成 Token 凭证与 Session 会话；
        //记录 Token 活跃时间；
        //通知全局侦听器，xx 账号登录成功；
        //将 Token 注入到请求上下文；
        Long loginInfoId = loginInfo.getId();
        StpUtil.login(loginInfoId);
        //获取saToken给的tokenName和tokenValue
        String tokenName = StpUtil.getTokenName();
        String tokenValue = StpUtil.getTokenValue();
        //查询当前用户权限
//        Long loginId = loginInfo.getId();
//        List<String> Sns= permissionService.selectSnByLoginId(loginId);
//        //将当前用户权限存入Redis中
//        String tokenKey = String.format(Constants.Redis.LOGIN_INFO_PERMISSIONS, loginId);
//        redisTemplate.opsForValue().set(tokenKey,Sns,tokenTimeout, TimeUnit.SECONDS);
        //返回用户基础信息、TokenName、TokenValue
        LoginContext loginContext = new LoginContext();
        BeanUtil.copyProperties(loginInfo,loginContext);
        LoginInfoDto loginInfoDto = new LoginInfoDto();
        loginInfoDto.setTokenName(tokenName);
        loginInfoDto.setTokenValue(tokenValue);
        loginInfoDto.setLoginContext(loginContext);

        String loginContextKey = String.format(Constants.Login.LOGIN_CONTEXT_KEY, loginInfoId);
        redisTemplate.opsForValue().set(loginContextKey,loginContext);
        return loginInfoDto;

    }

    @Override
    public void appLogOut() {
        long loginId = StpUtil.getLoginIdAsLong();
        String key = String.format(Constants.Login.LOGIN_CONTEXT_KEY, loginId);
        redisTemplate.delete(key);
    }

    @Override
    public LoginInfoDto adminLogin(AdminLoginDto login) {
        Login loginInfo = super.getOne(new LambdaQueryWrapper<Login>().eq(Login::getUsername, login.getUsername()));
        //账号是否存在
        AssertUtil.isNotNull(loginInfo, "账号不存在！");
        //密码是否正确
        boolean checkResult = BCrypt.checkpw(login.getPassword(), loginInfo.getPassword());
        AssertUtil.isTrue( checkResult,"密码错误");

        Long loginId = loginInfo.getId();
        List<String> Sns= permissionService.selectSnByLoginId(loginId);
        //将当前用户权限存入Redis中
        StpUtil.login(loginInfo.getId());
        String tokenName = StpUtil.getTokenName();
        String tokenValue = StpUtil.getTokenValue();
        long tokenTimeout = StpUtil.getTokenTimeout();
        String tokenKey = String.format(Constants.Redis.LOGIN_INFO_PERMISSIONS, loginId);
        if(!ObjectUtil.isEmpty(Sns)){
        redisTemplate.opsForValue().set(tokenKey,Sns,tokenTimeout, TimeUnit.SECONDS);
        }

        //返回用户基础信息、TokenName、TokenValue
        LoginContext loginContext = new LoginContext();
        BeanUtil.copyProperties(loginInfo,loginContext);
        LoginInfoDto loginInfoDto = new LoginInfoDto();
        loginInfoDto.setTokenName(tokenName);
        loginInfoDto.setTokenValue(tokenValue);
        loginInfoDto.setLoginContext(loginContext);

        return loginInfoDto;

    }

    @Override
    public void adminLogout() {
        long loginIdAsLong = StpUtil.getLoginIdAsLong();
        System.out.println(loginIdAsLong);
        //删除 localstorage中的logininfo
        StpUtil.logout(loginIdAsLong);
        //删除redis中存储的token
        String tokenKey = String.format(Constants.Redis.LOGIN_INFO_PERMISSIONS, loginIdAsLong);
        redisTemplate.delete(tokenKey);

    }

    public static void main(String[] args) {
        String salt = BCrypt.gensalt(10);
        String hashpw = BCrypt.hashpw("123456", salt);
        System.out.println(hashpw);
    }
}
